// 建立三个 Account 到 chain 中
abstract class Account {
  Account? _successor;
  final double _balance; //账户中现有的钱

  Account(this._balance);

  // 让用户可以自行调整 chain 中下一个 Account
  void setNext(Account next) {
    _successor = next;
  }

  String pay(double amountToPay) {
    if (canPay(amountToPay)) {
      // 当前账户有足够的钱（权限）去处理用户支付请求
      return "Paid $amountToPay using ${runtimeType.toString()}";
    } else if (_successor != null) {
      // 现在账户的钱不够，由用户指定的下一个账户去支付
      var reject =
          "Cannot pay using ${this.runtimeType.toString()}. Proceeding ... \n";
      reject += _successor!.pay(amountToPay);
      return reject;
    } else {
      // 用户未再指定账户，调用结束
      return "None of the accounts have enough balance";
    }
  }

  // 检查当前账户能否支付（权限）
  bool canPay(double amountToPay) => _balance >= amountToPay;
}

class Bank extends Account {
  Bank(double balance) : super(balance);
}

class Paypal extends Account {
  Paypal(double balance) : super(balance);
}

class Bitcoin extends Account {
  Bitcoin(double balance) : super(balance);
}

/*
责任链模式

目的
帮助串联实体，并且在 Request 时从最前面的实体往后找起，直到找到可以符合条件的实体。
假设你有 A, B, C 三个帐户，要求消费时由 A 开始扣款，如果 A 不够再去找 B , C 。

何时使用
如果有多个实体可以用来处理 request ，并且想要他们有优先顺序时。
 */
void main(List<String> args) {
  // 添加一个 Account到 chain 中（chain即抽象类Account本身）
  Account bank = Bank(100); //100余额（权限/能力/责任）
  Account paypal = Paypal(200); //200余额
  Account bitcoin = Bitcoin(300); //300余额

  // 此处构建责任链
  bank.setNext(paypal);
  paypal.setNext(bitcoin);

  // ? 也可以考虑使用一个数组[]构建责任链
  // ? 即先将所有的 Account 按顺序加入到 chain 中，然后再依序调用构建成链

  // 从 chain 的第一个对象开始支付
  print(bank.pay(259));

  // ChainOfResponsibility👇👇👇
  // Cannot pay using Bank. Proceeding ...
  // Cannot pay using Paypal. Proceeding ...
  // Paid 259.0 using Bitcoin
}
